"""
扫描服务模块
提供扫描任务的核心业务逻辑
"""

import os
import asyncio
import traceback
from datetime import datetime
from typing import Optional, List, Dict, Any

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, text, desc

from db.models.scan import ScanTask, ScanResult, AIAnalysisResult, ScanRecord
from schemas.base import ScanRequest, ScanResultDetailRequest
from services.scanner.scanner import Scanner
from core.utils.file_utils import generate_temp_dir, ensure_temp_dir_exists, check_dir_age, remove_expired_dir


class ScanService:
    """扫描服务类"""
    
    def __init__(self, db: AsyncSession):
        self.db = db
    
    async def start_scan(self, request: ScanRequest) -> Dict[str, Any]:
        """
        启动扫描任务
        
        Args:
            request: 扫描请求
            
        Returns:
            包含任务ID的响应字典
        """
        print(f"\n收到扫描请求:")
        print(f"仓库地址: {request.repo_url}")
        print(f"分支: {request.branch}")
        print(f"扫描类型: {request.scan_type}")

        try:
            # 生成临时目录
            temp_dir = generate_temp_dir(request.repo_url, request.branch)
            print(f"临时目录: {temp_dir}")

            # 检查目录是否存在
            if os.path.exists(temp_dir):
                # 检查目录是否过期（超过24小时）
                if check_dir_age(temp_dir, 24):
                    print(f"目录已过期，重新克隆: {temp_dir}")
                    remove_expired_dir(temp_dir)
                    ensure_temp_dir_exists(temp_dir)
                else:
                    print(f"使用已存在的目录: {temp_dir}")
            else:
                ensure_temp_dir_exists(temp_dir)

            # 创建扫描任务
            task_id = await self._create_scan_task(request)
            print(f"创建任务成功: {task_id}")

            return {
                "task_id": task_id,
                "message": "扫描任务已启动",
                "status": "pending"
            }

        except Exception as e:
            print(f"启动扫描任务时发生错误: {str(e)}")
            print(f"错误类型: {type(e).__name__}")
            print(f"错误堆栈: {traceback.format_exc()}")
            raise
    
    async def _create_scan_task(self, request: ScanRequest) -> int:
        """
        创建扫描任务
        
        Args:
            request: 扫描请求
            
        Returns:
            任务ID
        """
        print("\n创建扫描任务...")
        
        # 直接执行INSERT语句并获取ID
        insert_result = await self.db.execute(
            text("""
                INSERT INTO scan_tasks (repo_url, branch, scan_type, status, created_at, updated_at) 
                VALUES (:repo_url, :branch, :scan_type, :status, :created_at, :updated_at)
            """),
            {
                "repo_url": request.repo_url,
                "branch": request.branch,
                "scan_type": request.scan_type,
                "status": "pending",
                "created_at": datetime.now(),
                "updated_at": datetime.now()
            }
        )
        
        await self.db.commit()
        print("任务插入完成")
        
        # 获取插入的ID
        id_result = await self.db.execute(text("SELECT LAST_INSERT_ID()"))
        task_id = id_result.scalar()
        print(f"获取到的任务ID: {task_id}")
        
        if not task_id or task_id == 0:
            # 如果LAST_INSERT_ID失败，通过查询获取
            print("LAST_INSERT_ID失败，尝试查询最新记录...")
            query_result = await self.db.execute(
                text("""
                    SELECT id FROM scan_tasks 
                    WHERE repo_url = :repo_url 
                    AND branch = :branch 
                    AND scan_type = :scan_type 
                    AND status = :status 
                    ORDER BY created_at DESC 
                    LIMIT 1
                """),
                {
                    "repo_url": request.repo_url,
                    "branch": request.branch,
                    "scan_type": request.scan_type,
                    "status": "pending"
                }
            )
            task_id = query_result.scalar()
            print(f"查询到的任务ID: {task_id}")
        
        if not task_id or task_id == 0:
            raise Exception("无法获取有效的任务ID")
        
        return task_id
    
    async def get_scan_list(self, filters: Dict[str, Any]) -> Dict[str, Any]:
        """
        获取扫描任务列表
        
        Args:
            filters: 筛选条件
            
        Returns:
            包含任务列表的响应字典
        """
        try:
            # 构建基础查询
            base_query = select(ScanTask)
            
            # 添加筛选条件
            if filters.get('repo_url'):
                base_query = base_query.where(ScanTask.repo_url.like(f"%{filters['repo_url']}%"))
            
            if filters.get('branch'):
                base_query = base_query.where(ScanTask.branch.like(f"%{filters['branch']}%"))
            
            if filters.get('scan_type'):
                base_query = base_query.where(ScanTask.scan_type == filters['scan_type'])
            
            if filters.get('status'):
                base_query = base_query.where(ScanTask.status == filters['status'])
            
            # 处理时间筛选条件
            base_query = await self._apply_time_filters(base_query, filters)
            
            # 获取总数
            count_query = select(func.count()).select_from(base_query.subquery())
            total_result = await self.db.execute(count_query)
            total = total_result.scalar()
            
            # 添加排序和分页
            page = filters.get('page', 1)
            page_size = filters.get('page_size', 10)
            query = base_query.order_by(desc(ScanTask.created_at))
            query = query.offset((page - 1) * page_size).limit(page_size)
            
            # 执行查询
            result = await self.db.execute(query)
            tasks = result.scalars().all()
            
            # 为每个任务获取问题总数
            task_list = []
            for task in tasks:
                issue_count_query = select(func.count(ScanResult.id)).where(ScanResult.task_id == task.id)
                issue_count_result = await self.db.execute(issue_count_query)
                total_issues = issue_count_result.scalar() or 0
                
                task_item = {
                    "id": task.id,
                    "repo_url": task.repo_url,
                    "branch": task.branch,
                    "scan_type": task.scan_type,
                    "status": task.status,
                    "created_at": task.created_at,
                    "updated_at": task.updated_at,
                    "total_issues": total_issues
                }
                task_list.append(task_item)
            
            return {
                "total": total,
                "page": page,
                "page_size": page_size,
                "items": task_list
            }
            
        except Exception as e:
            print(f"获取扫描任务列表时发生错误: {str(e)}")
            raise
    
    async def _apply_time_filters(self, base_query, filters: Dict[str, Any]):
        """
        应用时间筛选条件
        
        Args:
            base_query: 基础查询
            filters: 筛选条件
            
        Returns:
            应用了时间筛选的查询
        """
        from core.utils.time_utils import parse_datetime, parse_time_range
        
        # 处理 start_time 和 end_time
        if filters.get('start_time') or filters.get('end_time'):
            if filters.get('start_time'):
                start_dt = parse_datetime(filters['start_time'])
                base_query = base_query.where(ScanTask.created_at >= start_dt)
            
            if filters.get('end_time'):
                end_dt = parse_datetime(filters['end_time'])
                base_query = base_query.where(ScanTask.created_at <= end_dt)
        
        # 处理 created_at_start 和 created_at_end
        elif filters.get('created_at_start') or filters.get('created_at_end'):
            if filters.get('created_at_start'):
                created_start_dt = parse_datetime(filters['created_at_start'])
                base_query = base_query.where(ScanTask.created_at >= created_start_dt)
            
            if filters.get('created_at_end'):
                created_end_dt = parse_datetime(filters['created_at_end'])
                base_query = base_query.where(ScanTask.created_at <= created_end_dt)
        
        # 处理 updated_at_start 和 updated_at_end
        if filters.get('updated_at_start') or filters.get('updated_at_end'):
            if filters.get('updated_at_start'):
                updated_start_dt = parse_datetime(filters['updated_at_start'])
                base_query = base_query.where(ScanTask.updated_at >= updated_start_dt)
            
            if filters.get('updated_at_end'):
                updated_end_dt = parse_datetime(filters['updated_at_end'])
                base_query = base_query.where(ScanTask.updated_at <= updated_end_dt)
        
        # 处理时间范围参数
        if filters.get('created_at_range'):
            start_time_str, end_time_str = parse_time_range(filters['created_at_range'])
            if start_time_str:
                created_start_dt = parse_datetime(start_time_str)
                base_query = base_query.where(ScanTask.created_at >= created_start_dt)
            if end_time_str:
                created_end_dt = parse_datetime(end_time_str)
                base_query = base_query.where(ScanTask.created_at <= created_end_dt)
        
        if filters.get('updated_at_range'):
            start_time_str, end_time_str = parse_time_range(filters['updated_at_range'])
            if start_time_str:
                updated_start_dt = parse_datetime(start_time_str)
                base_query = base_query.where(ScanTask.updated_at >= updated_start_dt)
            if end_time_str:
                updated_end_dt = parse_datetime(end_time_str)
                base_query = base_query.where(ScanTask.updated_at <= updated_end_dt)
        
        return base_query
    
    async def get_scan_result(self, task_id: int) -> Dict[str, Any]:
        """
        获取扫描结果
        
        Args:
            task_id: 任务ID
            
        Returns:
            包含扫描结果的响应字典
        """
        try:
            # 获取任务信息
            task = await self.db.get(ScanTask, task_id)
            if not task:
                raise ValueError("任务不存在")
            
            # 获取扫描结果
            results = await self.db.execute(
                select(ScanResult).where(ScanResult.task_id == task_id)
            )
            results = results.scalars().all()
            
            # 转换为响应格式
            result_list = []
            for result in results:
                result_item = {
                    "id": result.id,
                    "task_id": result.task_id,
                    "file_path": result.file_path,
                    "function_name": result.function_name,
                    "start_line": result.start_line,
                    "end_line": result.end_line,
                    "issue_type": result.issue_type,
                    "severity": result.severity,
                    "message": result.message,
                    "suggestion": result.suggestion,
                    "created_at": result.created_at
                }
                result_list.append(result_item)
            
            return {
                "id": task.id,
                "repo_url": task.repo_url,
                "branch": task.branch,
                "scan_type": task.scan_type,
                "status": task.status,
                "created_at": task.created_at,
                "updated_at": task.updated_at,
                "results": result_list
            }
            
        except Exception as e:
            print(f"获取扫描结果时发生错误: {str(e)}")
            raise 